#include "stm32f10x.h"
#include "freertos.h"
#include "task.h"
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include <stdbool.h>
#include "UART2.h"
#include "UART3.h"
#include "OLED.h"
#include "HC05.h"
#include "ADC.h"

// LED状态灯部分

// 新增宏定义（注意引脚修改）
#define LED_RED_ON()    GPIO_ResetBits(GPIOB, GPIO_Pin_3)
#define LED_RED_OFF()   GPIO_SetBits(GPIOB, GPIO_Pin_3)
#define LED_YELLOW_ON() GPIO_ResetBits(GPIOB, GPIO_Pin_5)
#define LED_YELLOW_OFF() GPIO_SetBits(GPIOB, GPIO_Pin_5)
#define LED_GREEN_ON()  GPIO_ResetBits(GPIOB, GPIO_Pin_4)
#define LED_GREEN_OFF() GPIO_SetBits(GPIOB, GPIO_Pin_4)

// 修改后的LED初始化函数
void LED_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    
    // 使能时钟（需要开启AFIO时钟进行重映射）
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO, ENABLE);

    // 禁用JTAG功能（释放PB3-PB5）
    GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);

    // 配置PB3/PB4/PB5为推挽输出
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
    GPIO_Init(GPIOB, &GPIO_InitStructure);
    
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
    GPIO_Init(GPIOB, &GPIO_InitStructure);
    
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
    GPIO_Init(GPIOB, &GPIO_InitStructure);

    // 初始状态：全灭
    LED_RED_OFF();
    LED_GREEN_OFF();
    LED_YELLOW_OFF();
}
// LED状态灯部分结束







// ------ Flash部分 -------
const uint32_t address = 0x0800F000;  // 指定Flash操作起始地址
int hasStoredCredential = 0;
char storedSSID[32] = {0};
char storedPass[64] = {0};


// Flash操作函数
// 擦除指定地址的Flash页。需先解锁才能操作。
void erasePage(uint32_t addr) {
    FLASH_Unlock();
    FLASH_ErasePage(addr);
    FLASH_Lock();
}

// 向Flash指定地址写入32位数据。需按字对齐。
void changeFlashFor32(uint32_t addr, uint32_t data) {
    FLASH_Unlock();
    FLASH_ProgramWord(addr, data);
    FLASH_Lock();
}

// 从指定Flash地址读取len字节到缓冲区。
void readFlash(uint32_t addr, char *bufferFlash, int len) {
    for (int i = 0; i < len; i++) {
        bufferFlash[i] = *(__IO uint8_t *)(addr + i);
    }
}
// ------- Flash部分结束 ----------


//int flag = 0;  // 标志位 当能够连接Wifi时候，函数可以继续向服务器发送数据
uint8_t RxSTA = 1;
char RxData[50] = "None";
char leftPart[50], rightPart[50];  
char buf_usart2[100] = {0};  // 用于暂存Wifi模块返回的AT命令

QueueHandle_t queue;


// 函数声明部分
// 从"!xxx=xxxxx!"中提取数据
void extractParts(const char *input, char *leftPart, char *rightPart);
// 向服务器发送数据
void SendPost(void);
// 按钮重置
void checkClearButton(void);
// 复位初始化
void reset_Init(void);
// 蜂鸣器初始化
void BUZZER_Init(void);
// 从ADC中提取温度和亮度数据
void extractData(const char* input, float *temperature, float *light);
// 判断AT指令响应结果
bool CheckATResult(const char* cmd, 
                        const char* success, 
                        const char* error, 
                        uint32_t timeout_ms);


char buffer[64];  // 存储ADC传感器数据
						
// 任务1： 读取ADC数据
void task1(void * arg) {	
	while(1){
		getMSG(buffer); // 获取ADC数据（用户提供的函数）
// 		此处可添加其他逻辑（如控制LED、存储数据等）
//		从ADC中提取温度和亮度进行检测
		float temperature, light;
		extractData(buffer, &temperature, &light);  
		
//		如果光照强度小于10%或大于80%时，蜂鸣器响
//		如果感测温度小于5'C或大于40'C时，蜂鸣器响
		if(light < 10 || light > 80 || temperature < 5 || temperature > 40){
			GPIO_ResetBits(GPIOA, GPIO_Pin_12);

			vTaskDelay(500);
			GPIO_SetBits(GPIOA, GPIO_Pin_12);
			
// 			红灯快速闪烁（200ms周期）
			LED_RED_ON();
			vTaskDelay(100);
			LED_RED_OFF();
			vTaskDelay(100);
		}
		
		vTaskDelay(1500);
	}
}

// 任务2：向服务器发送读取的数据 
void task2(void * arg) {
	
	
	LED_GREEN_ON();    // 系统启动指示
	vTaskDelay(500);
	LED_GREEN_OFF();
	
	LED_YELLOW_ON();
 	
	int flag = 0;  // 标志位 当能够连接Wifi时候，函数可以继续向服务器发送数据
	int isFirstConnect = 1;  // 标志位 第一次连接
	while (1)
	{
		OLED_ShowString(1, 1, "RxData:");
		OLED_ShowString(2, 1, RxData);
		HC05_GetData(RxData);
		
// 		若有存储数据并且是第一次连接，就进来做服务器发送准备操作
		if(hasStoredCredential && isFirstConnect) {
			vTaskDelay(100);
			memset(buf_usart2, 0, sizeof(buf_usart2));
			printf3("-----------------------------------------\n");
			printf3("--------- Checking network... -----------\n");
			printf3("-----------------------------------------\n");
			// 检查连接状态，并判断是否连接到Wifi
			if (CheckATResult("AT+CWJAP?", "OK", "FAIL", 15000)) {
				printf3("Wifi Connected :)\n");
				OLED_ShowString(4, 1, "Wifi OK :)");
//				flag = 1;  // 标志位
//				isFirstConnect = 0;   // 标志位 成功连接则将第一次置零,等会要移动到TCP部分
				OLED_ShowString(3, 1, "                ");
				// WiFi连接成功时
				LED_YELLOW_OFF();
				LED_GREEN_ON();
			} else {
				printf3("Wifi Fail :(\n");
				OLED_ShowString(4, 1, "Wifi Fail :(");
				flag = 0;
				
				// 当连接失败时
				LED_RED_ON();
				LED_GREEN_OFF();
			}
			// 清空自己定义的缓冲区，以便下次使用
			memset(buf_usart2, 0, sizeof(buf_usart2));
			printf3("-----------------------------------------\n");

					
//			4.开启透传模式(准备收发TCP数据)				
			printf2("AT+CIPMODE=1\r\n");
			vTaskDelay(500);	
//			printf3("Receive2:\n%s", buf_usart2);	
//			printf3("Receive2 Length: %d\n", strlen(buf_usart2));
			memset(buf_usart2, 0, sizeof(buf_usart2));	

//			5.建立TCP连接, 连接到47.115.220.165的9004端口		
			if (CheckATResult("AT+CIPSTART=\"TCP\",\"47.115.220.165\",9004\r\n", "OK", "ERROR", 10000)) {
				printf3("TCP Connected :)\n");
				OLED_ShowString(4, 1, "                ");
				OLED_ShowString(4, 1, "TCP OK :)");
				flag = 1;
				isFirstConnect = 0;   // 标志位 成功连接则将第一次置零
				
				// 当连接成功时
				LED_RED_OFF();
				LED_GREEN_ON();
				
			} else {
				printf3("TCP Disconnected :(\n");
				OLED_ShowString(4, 1, "                ");
				OLED_ShowString(4, 1, "TCP Fail :(");
				flag = 0;  // 标志位
				
				// 当连接失败时
				LED_RED_ON();
				LED_GREEN_OFF();
				
			}
						
		}
		
		
		if (RxSTA == 0)
		{
//          OLED显示一些状态
			OLED_Clear();
			OLED_ShowString(1, 1, "RxData:");
			OLED_ShowString(2, 1, RxData);
			extractParts(RxData, leftPart, rightPart);  // 从蓝牙传过来的数据中提取Wifi名和密码
			printf3("%s\n",RxData);	
			printf3("left: %s\n", leftPart);
			printf3("right %s\n", rightPart);
			
			
//          1.开始发送AT指令			
			if (CheckATResult("AT\r\n", "OK", "ERROR", 5000)) {
				printf3("AT OK :)\n");
//				OLED_ShowString(4, 1, "AT OK :)");
			} else {
				printf3("AT Fail :(\n");
//				OLED_ShowString(4, 1, "AT Fail :(");
			}
			// 清空自己定义的缓冲区，以便下次使用
			memset(buf_usart2, 0, sizeof(buf_usart2));			
			


//          2.配置网络连接, 连接到自己输入的网络(pro)	

//			要开始连接wifi了			
			LED_YELLOW_ON();
			LED_GREEN_OFF();
			LED_RED_OFF();
					
			printf3("BT Connecting to the network..........\n");
			char command[100]; // 确保数组大小足够容纳最终字符串			
			sprintf(command, "AT+CWJAP_DEF=\"%s\",\"%s\"\r\n", leftPart, rightPart);	
			if (CheckATResult(command, "OK", "ERROR", 15000)) {
				printf3("Wifi Connected :)\n");
				OLED_ShowString(4, 1, "Wifi OK :)");
				flag = 0;  // 标志位
				hasStoredCredential = 1;  // 标志位 方便第二次循环时可以进去  上面的if(xx & xx)
		
				
// 				开始Flash写数据				
				uint32_t status = *((__IO uint32_t *)(address));  // 读取Flash首字状态
				char bufferFlashBT[40] = {0};    // 数据缓冲区
				
				LED_YELLOW_ON();  // 黄灯亮起
				
				// 第一次用蓝牙时候就可以准备写进去了，里面也不会有数据
				// 当第二次按到蓝牙，如果里面有数据就不写，没有就写
				if (status != 0xFFFFFFFF) {
					int len = *((__IO uint32_t *)(address + 4));
					readFlash(address + 8, bufferFlashBT, len);
					extractParts(bufferFlashBT, storedSSID, storedPass);
// 					直接使用存储的凭证连接
					printf2("AT+CWJAP_DEF=\"%s\",\"%s\"\r\n", storedSSID, storedPass);
					printf3("BT Read: state=%lu length=%d data=%s\r\n", status, len, bufferFlashBT);
				} else {  // Flash存储没有数据，写入Flash
//					char *str = "!hzh=12345678!";  // 要写入的数据
//					strncpy(bufferFlashBT, str, strlen(str));
					printf3("BT Flash Writing...\n");
					strncpy(bufferFlashBT, RxData, strlen(RxData));
					erasePage(address);
					changeFlashFor32(address, 14);
					changeFlashFor32(address + 4, strlen(bufferFlashBT));
					for (int i = 0; i < sizeof(bufferFlashBT); i += 4) {
						changeFlashFor32(address + 8 + i, *(int *)(bufferFlashBT + i));
					}
					printf3("BT Flash Write OK!\r\n");
				}				
// 				Flash写完了	
				LED_YELLOW_OFF();  // 黄灯熄灭
				// WiFi连接成功时
				LED_YELLOW_OFF();
				LED_GREEN_ON();						
				
			} else {
				printf3("Wifi Fail :(\n");
				OLED_ShowString(4, 1, "Wifi Fail :(");
				flag = 0;
				
				printf3("Enter WiFi again.\n");
			}
			// 清空自己定义的缓冲区，以便下次使用
			memset(buf_usart2, 0, sizeof(buf_usart2));			
			
	
//			清理左右部分的输入
			memset(leftPart, 0, sizeof(leftPart));
			memset(rightPart, 0, sizeof(rightPart));
// 			最后清空显示屏里面RxData的内容
			memset(RxData, 0, sizeof(RxData));
			RxSTA = 1;

		}
		
		// 若连接了网络就进来发送
		if(flag == 1)
		{
			SendPost();
			vTaskDelay(1000);
		}
		
	}	
	
}


// 任务3 长按PB12上的按钮 8秒清除Flash
void task3(void* arg) {
    while(1) {
        checkClearButton();
//      vTaskDelay(100);
		vTaskDelay(150);
    }
}

int main(void) {
	
    USART2_Init();
	USART3_Init();
	OLED_Init();
	HC05_Init();
	AD_Init(); 
	reset_Init();
	BUZZER_Init();
	LED_Init();
	
	
    char bufferFlash[40] = {0};    // 数据缓冲区
	uint32_t status = *((__IO uint32_t *)(address));  // 读取Flash首字状态
	
	
	printf3("Welcome!\n\n");
	
	
	// Flash部分
    if (status != 0xFFFFFFFF) {
		printf3("Use stored Wifi\n");
        int len = *((__IO uint32_t *)(address + 4));
        readFlash(address + 8, bufferFlash, len);
		extractParts(bufferFlash, storedSSID, storedPass);
// 		直接使用存储的凭证连接
		hasStoredCredential = 1;  // 标志位
		
		// 当开始连接WiFi时（在CheckATResult之前）：
		LED_YELLOW_ON();
		LED_RED_OFF();

//		char command2[100]; // 确保数组大小足够容纳最终字符串			
//		sprintf(command2, "AT+CWJAP_DEF=\"%s\",\"%s\"\r\n", storedSSID, storedPass);	
//		if (CheckATResult(command2, "OK", "ERROR", 15000)) {
//			printf3("Wifi Connected :)\n");
//			OLED_ShowString(4, 1, "Wifi OK :)");
//		} else {
//			printf3("Wifi Fail :(\n");
//			OLED_ShowString(4, 1, "Wifi Fail :(");
//		}		
        printf2("AT+CWJAP_DEF=\"%s\",\"%s\"\r\n", storedSSID, storedPass);
		
        printf3("Read: \nstate = %lu \nlength = %d \ndata = %s\r\n\r\n", status, len, bufferFlash);
		
		OLED_ShowString(3, 1, "Use stored Wifi");
	} else {
        OLED_ShowString(3, 1, "Waiting BT...");
    } 
	
    queue = xQueueCreate(60, 1);

    xTaskCreate(task1, "Task1", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY + 1, NULL);
    xTaskCreate(task2, "Task2", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY + 1, NULL);
	xTaskCreate(task3, "Task3", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY + 1, NULL);
    vTaskStartScheduler();

    while (1) {
    }

}



// 提取Wifi字符串信息
void extractParts(const char *input, char *leftPart, char *rightPart) {
    int equalPos = -1;
    int len = strlen(input);

    // 查找等号位置
    for (int i = 0; i < len; i++) {
        if (input[i] == '=') {
            equalPos = i;
            break;
        }
    }

    // 如果没有找到等号，则返回
    if(equalPos == -1){
        printf3("No equal sign was found！\n");
        return;
    }

    // 提取等号左边部分
    strncpy(leftPart, input + 1, equalPos - 1); // 跳过开头的'!'，所以是input + 1
    leftPart[equalPos - 1] = '\0'; // 添加结束符

    // 提取等号右边部分
    strcpy(rightPart, input + equalPos + 1);
    rightPart[strlen(rightPart) - 1] = '\0'; // 去除结尾的'!'
}

// 用于向服务器发送数据
void SendPost()
{	
//	6.开始准备发送数据		
	if (CheckATResult("AT+CIPSEND\r\n", "OK", "ERROR", 5000)) {
		printf3("AT+CIPSEND OK :)\n");
//				OLED_ShowString(4, 1, "AT+CIPSEND OK :)");
		LED_YELLOW_OFF();  // 发送成功黄灯闭
	} else {
		printf3("AT+CIPSEND Fail :(\n");
//				OLED_ShowString(4, 1, "AT+CIPSEND Fail :(");
		LED_YELLOW_ON();   // 发送失败黄灯亮
	}
		
	printf3("<<< Sending begins >>>\n");	
	memset(buf_usart2, 0, sizeof(buf_usart2));	
	
// 	6.1 发送数据
	printf2("%s\n", buffer);
	printf3("%s\n", buffer);
	vTaskDelay(300);
	
//	8.退出透传模式			
	printf2("+++");
	vTaskDelay(1000);
	vTaskDelay(1000);
	vTaskDelay(1000);
	printf3("Receive2 Length: %d\n", strlen(buf_usart2));
	printf3(">>> Sending ended <<<\n");	
	memset(buf_usart2, 0, sizeof(buf_usart2));	

}

void reset_Init(){
	// 初始化PB13为上拉输入
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
    GPIO_InitTypeDef GPIO_InitStruct = {
        .GPIO_Pin = GPIO_Pin_13,
        .GPIO_Mode = GPIO_Mode_IPU  // 上拉输入模式
    };
    GPIO_Init(GPIOB, &GPIO_InitStruct);
}

void BUZZER_Init(){
	// 1.开启GPIOA外设时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);

    // 2.1 初始化GPIO_InitTypeDef结构体,设置工作模式和输出速度
    GPIO_InitTypeDef GPIO_InitStruct;   // GPIO_InitStruct是一个习惯命名
    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_12;     // 初始化PA12
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;      // 工作速度为高速50MHz
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;   // 引脚的工作模式是推挽输出模式
    // 2.2 调用GPIO_Init, 完成PB15引脚初始化
    GPIO_Init(GPIOA, &GPIO_InitStruct);
	
	// 先关掉蜂鸣器
	GPIO_SetBits(GPIOA, GPIO_Pin_12);
}

void extractData(const char* input, float *temperature, float *light) {
    // 使用 sscanf 从输入字符串中提取温度和百分比
    sscanf(input, "Temp: %f'C, Light: %*[^()](%f%%)", temperature, light);
}

// 检查清除按钮是否被长按，若长按超过8秒则擦除指定页并系统复位（增加防抖处理）
void checkClearButton() {
    static uint32_t pressTime = 0;       // 有效按压起始时间戳
    static uint32_t debounceStart = 0;    // 防抖开始时间戳
    static bool isDebouncing = false;     // 防抖状态标志

    /* 检测GPIOB_13引脚状态（按钮物理状态）*/
    if(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_13) == 0) {
        /*---------- 防抖处理阶段 ----------*/
        if(!isDebouncing) {
            // 首次检测到低电平，记录防抖起始时间
            debounceStart = xTaskGetTickCount();
            isDebouncing = true;
        } 
        else if((xTaskGetTickCount() - debounceStart) > 20) {
            /* 通过20ms防抖期（假设1 tick=1ms）后确认有效按压 */
            
            /*---------- 长按检测阶段 ----------*/
            if(pressTime == 0) {
                // 记录有效按压起始时间（防抖后）
                pressTime = xTaskGetTickCount();
				LED_YELLOW_ON();
				printf3("Button Held 8 Seconds to Clear...\r\n");
            }
          
            // 检测持续按压时间是否超过8秒
            if((xTaskGetTickCount() - pressTime) > 8000) {
                erasePage(address);      // 擦除存储页（高风险操作）
//                NVIC_SystemReset();      // 触发系统级复位

//				flag = 0;  //顺便停止发送循环
				printf3("---------- Flash Cleared! ------------\r\n\r\n");
				LED_YELLOW_OFF();
            }
        }
    } 
    /*---------- 按钮释放处理 ----------*/
    else {
        isDebouncing = false;  // 重置防抖状态
        pressTime = 0;         // 重置长按计时
//		printf3("Operation Cancel!\r\n");
    }
}

// AT指令响应结果判断
bool CheckATResult(const char* cmd, 
                        const char* success, 
                        const char* error, 
                        uint32_t timeout_ms)
{

    printf2("%s", cmd);  // 发送AT指令

    TickType_t start = xTaskGetTickCount();
    const TickType_t timeout = pdMS_TO_TICKS(timeout_ms);
    bool connected = false;
    bool responded = false;

    while ((xTaskGetTickCount() - start) < timeout) {
        if (strstr(buf_usart2, success)) {
            connected = true;
            responded = true;
            break;
        }
        if (strstr(buf_usart2, error)) {
            connected = false;
            responded = true;
            break;
        }
        vTaskDelay(pdMS_TO_TICKS(100));
    }

	if (!responded){
		printf3("Timeout waiting for response!\n");
	}
    // 调试信息输出
    printf3("Received: \n%s\nLength: %d\n\n", buf_usart2, strlen(buf_usart2));
    return connected;
}
